import {messages} from "share/common";
import React, { Component, PropTypes } from "react"
import SelectHoc from "components/transfer/select-hoc"
import List from "components/transfer/list"
import Operation from "components/transfer/Operation"
import 'styles/components/transfer/index.scss'

@SelectHoc
class Transfer extends Component {

  separateDataSource() {
    const { dataSource, rowKey, targetKeys = [] } = this.props;
    const leftDataSource = [];
    const rightDataSource = new Array(targetKeys.length);
    dataSource.forEach(record => {
      if (rowKey) {
        record.key = rowKey(record);
      }
      const indexOfKey = targetKeys.indexOf(record.key);
      if (indexOfKey !== -1) {
        rightDataSource[indexOfKey] = record;
      } else {
        leftDataSource.push(record);
      }
    });
    return {
      leftDataSource,
      rightDataSource,
    };
  }

  handleListStyle = (listStyle, direction) => {
    if (typeof listStyle === 'function') {
      return listStyle({ direction });
    }
    return listStyle;
  };

  handleFilter = (direction, value) => {
    const { onSearch } = this.props;
    if (onSearch) {
      onSearch(direction, value);
    }
  };

  onItemSelect = (direction, selectedKey, checked) => {
    const { sourceSelectedKeys, targetSelectedKeys, setSource, selectedKeys, single } = this.props;
    const holder = single ? [selectedKey] :
                   direction === 'left' ? [...sourceSelectedKeys] : [...targetSelectedKeys];
    const index = holder.indexOf(selectedKey);
    if (index > -1) {
      holder.splice(index, 1);
    }
    if (checked) {
      holder.push(selectedKey);
    }
    this.handleSelectChange(direction, holder);
    if (!selectedKeys) {
      setSource(this.getSelectedKeysName(direction), holder);
    }
  };

  onAllSelect = (direction, resultKeys) => {
    const { setSource, selectedKeys } = this.props;
    this.handleSelectChange(direction, resultKeys);
    if (!selectedKeys) {
      setSource(this.getSelectedKeysName(direction), resultKeys);
    }
  };

  getSelectedKeysName = direction => {
    return direction === 'left' ? 'sourceSelectedKeys' : 'targetSelectedKeys';
  };

  handleSelectChange = (direction, holder) => {
    const { sourceSelectedKeys, targetSelectedKeys, onSelectChange } = this.props;
    if (!onSelectChange) {
      return;
    }
    if (direction === 'left') {
      onSelectChange(targetSelectedKeys, holder);
    } else {
      onSelectChange(sourceSelectedKeys, holder);
    }
  };

  moveTo = direction => {
    const { targetKeys = [], dataSource = [], onChange, sourceSelectedKeys, targetSelectedKeys, setSource,
      single } = this.props;
    const moveKeys = direction === 'right' ? sourceSelectedKeys : targetSelectedKeys;
    const newMoveKeys = moveKeys.filter(
      key => dataSource.some(data => key === data.key),
    );
    const newTargetKeys =
      direction === 'right'
        ? (single ? [...newMoveKeys] : [...new Set(newMoveKeys.concat(targetKeys))])
        : targetKeys.filter(targetKey => newMoveKeys.indexOf(targetKey) === -1);
    const oppositeDirection = direction === 'right' ? 'left' : 'right';
    setSource(this.getSelectedKeysName(oppositeDirection), []);
    this.handleSelectChange(oppositeDirection, []);
    if (onChange) {
      onChange(newTargetKeys, direction, newMoveKeys);
    }
  };

  render() {
    const { className, style, titles, listStyle, render, showSearch, children, sourceSelectedKeys,
      targetSelectedKeys, searchPlaceholder, labelKey, showSelectAll, extraSearch, searchValue } = this.props;
    const { leftDataSource, rightDataSource } = this.separateDataSource();
    return (
      <div className={this.classNames([className, 'transfer'])} style={style}>
        <List
          titleText={titles[0]}
          dataSource={leftDataSource}
          showSearch={showSearch}
          extraSearch={extraSearch}
          style={this.handleListStyle(listStyle, 'left')}
          render={render}
          direction="left"
          checkedKeys={sourceSelectedKeys}
          handleFilter={e => this.handleFilter('left', e.target.value)}
          onItemSelect={(selectedKey, checked) => this.onItemSelect('left', selectedKey, checked)}
          onAllSelect={selectedKey => this.onAllSelect('left', selectedKey)}
          renderList={children}
          searchPlaceholder={searchPlaceholder}
          labelKey={labelKey}
          searchValue={searchValue}
          showSelectAll={showSelectAll('left')}
        />
        <Operation
          leftActive={targetSelectedKeys.length > 0}
          rightActive={sourceSelectedKeys.length > 0}
          moveToRight={() => this.moveTo('right')}
          moveToLeft={() => this.moveTo('left')}
        />
        <List
          titleText={titles[1]}
          dataSource={rightDataSource}
          showSearch={showSearch}
          extraSearch={extraSearch}
          style={this.handleListStyle(listStyle, 'right')}
          render={render}
          direction="right"
          checkedKeys={targetSelectedKeys}
          handleFilter={e => this.handleFilter('right', e.target.value)}
          onItemSelect={(selectedKey, checked) => this.onItemSelect('right', selectedKey, checked)}
          onAllSelect={selectedKey => this.onAllSelect('right', selectedKey)}
          renderList={children}
          searchPlaceholder={searchPlaceholder}
          labelKey={labelKey}
          searchValue={searchValue}
          showSelectAll={showSelectAll('right')}
        />
      </div>
    )
  }

  static propTypes = {
    dataSource: PropTypes.array.isRequired,
    titles: PropTypes.array,
    style: PropTypes.object,
    listStyle: PropTypes.func,
    render: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,
    showSearch: PropTypes.bool,
    searchPlaceholder: PropTypes.string,
    onChange: PropTypes.func,
    onSelectChange: PropTypes.func,
    onSearch: PropTypes.func,
    rowKey: PropTypes.func.isRequired,
    selectedKeys: PropTypes.array,
    labelKey: PropTypes.string,
    showSelectAll: PropTypes.func,
    extraSearch: PropTypes.func,
    searchValue: PropTypes.func,
    single: PropTypes.bool
  };

  static defaultProps = {
    dataSource: [],
    locale: {},
    showSearch: false,
    listStyle: () => {},
    titles: [messages('common-1.key291')/*待选列表*/, messages('common-1.key293')/*已选列表*/],
    searchPlaceholder: '',
    showSelectAll: () => false,
    extraSearch: () => {},
    searchValue: () => {},
    single: false
  };

}

export default Transfer
